/**
 * 
 */
package com.asm.examples;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;

import org.apache.commons.lang.StringUtils;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

/**
 * @author lionbule
 * 
 */
public class TestSimpleInteger extends ClassLoader implements Opcodes {

	public static void main(String[] args) throws Exception {
		String className = "ExamplePerson";
		String fieldName = "age";

		byte[] code = createClassInt(className, fieldName);
		
		
		TestSimpleInteger loader = new TestSimpleInteger();
		Class<?> exampleClass = loader.defineClass(className, code, 0,
				code.length);
		
		Object invoker = exampleClass.newInstance();
		
		String setMethodName = "set" + StringUtils.capitalize(fieldName);
		String getMethodName = "get" + StringUtils.capitalize(fieldName);
		
		Method setMethod = exampleClass.getMethod(setMethodName, new Class[]{int.class});
		setMethod.invoke(invoker, new Object[]{new Integer(123456789)}); 
		
		Method getMethod = exampleClass.getMethod(getMethodName, new Class[]{}); 
		System.out.println(getMethod.invoke(invoker, new Object[]{}));
	}

	private static byte[] createClassInt(String className, String fieldName)
			throws IOException {
		ClassWriter cw = new ClassWriter(0);

		cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);
		// creates a MethodWriter for the (implicit) constructor
		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,
				null);
		// pushes the 'this' variable
		mv.visitVarInsn(ALOAD, 0);
		// invokes the super class constructor
		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
		mv.visitInsn(RETURN);
		// this code uses a maximum of one stack element and one local
		// variable
		mv.visitMaxs(1, 1);

		addMethod(cw, mv, className, fieldName);
		
		byte[] code = cw.toByteArray();
		FileOutputStream fos = new FileOutputStream(className + ".class");
		fos.write(code);
		fos.close();

		return code;
	}
	
	private static void addMethod(ClassWriter cw, MethodVisitor mv, String className, String fieldName){
        String setMethodName = "set" + StringUtils.capitalize(fieldName);
        String getMethodName = "get" + StringUtils.capitalize(fieldName);

        cw.visitField(ACC_PRIVATE, fieldName, "I", null, 0);

        // setMethod
        mv = cw.visitMethod(ACC_PUBLIC, setMethodName, "(I)V", null, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitVarInsn(ILOAD, 1);
        mv.visitFieldInsn(PUTFIELD, className, fieldName, "I");
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 2);

        // getMethod
        mv = cw.visitMethod(ACC_PUBLIC, getMethodName, "()I", null, null);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, className, fieldName, "I");
        mv.visitInsn(IRETURN);
        mv.visitMaxs(1, 1);
	}
	
    
    public static enum FieldType{
        
    }
    
}
